<?php

namespace Renshan\DetectorBundle\Service;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Doctrine\ORM\Query\ResultSetMapping;
use Renshan\DetectorBundle\Entity\ReqGroup as GroupEntity;
use Renshan\UserBundle\Entity\User;
use Renshan\UserBundle\Service\User as UserService;
use Renshan\DetectorBundle\Entity\Result as ResultEntity;
use Renshan\Http\Request;
use Renshan\Http\Response;
use Renshan\Http\Headers;

class ReqGroup
{
    private $container;
    private $request;
    private $user_service;
    private $results = [];

    /**
     *
     * 构造启，参数由依赖注入自动传入
     */
    public function __construct(ContainerInterface $container, RequestStack $requst_stack, UserService $user_service)
    {
        $this->container    = $container;
        $this->request      = $requst_stack->getCurrentRequest();
        $this->user_service = $user_service;
    }

    /**
     *
     * 创建一个探测分组
     *
     * @return array
     */
    public function create()
    {
        $ret_array = ['code' => -1];

        $params = $this->request->get('params');

        if ($params === null) {
            $ret_array['message'] = '参数不能为空';
            return $ret_array;
        }

        $params = json_decode($params, true);

        if (json_last_error() !== 0) {
            $ret_array['message'] = '参数格式错误';
            return $ret_array;
        }

        /** 数据不全 **/
        if (!array_key_exists('title', $params) || !array_key_exists('timing', $params) || !array_key_exists('keys', $params)) {
            $ret_array['message'] = '参数不完整';
            return $ret_array;
        }

        /** 少于2个接口不能作为一组 **/
        if (count($params['keys']) < 2) {
            $ret_array['message'] = '接口个数必须大于1';
            return $ret_array;
        }

        $keys = $params['keys'];

        $em = $this->container->get('doctrine')->getManager();

        $in = '';

        foreach ($keys as $key) {
            $in .= $key . ', ';
        };

        $in = rtrim($in, ", ");

        $query = $em->createQuery("SELECT t FROM Renshan\DetectorBundle\Entity\Target t WHERE t.id IN($in)");

        $targets = $query->getResult();

        if (count($targets) === 0) {
            $ret_array['message'] = '无接口数据';
            return $ret_array;
        }

        $user       = $this->user_service->getUser();
        $avaliable  = [];

        foreach ($targets as $target) {
            if ($target->getUser()->getId() !== $user->getId()) {
                continue;
            }

            array_push($avaliable, $target);
        }

        if (count($avaliable) === 0) {
            $ret_array['message'] = '无接口数据';
            return $ret_array;
        }

        $group = new GroupEntity();
        $group->setTitle($params['title']);
        $group->setTiming($params['timing']);
        $group->setTimes(0);
        $group->setUser($user);

        foreach ($avaliable as $target) {
            $group->addTarget($target);
            $target->addReqGroup($group);
            $em->persist($target);
        }

        $em->persist($group);
        $em->flush();

        return ['code' => 1];
    }

    /**
     *
     * 获取某个用户的分组个数
     *
     * @param Renshan\UserBundle\Entity\User $user
     *
     * @return integer
     */
    public function count()
    {
        $user = $this->user_service->getUser();

        $em = $this->container->get('doctrine')->getManager();

        $query = $em->createQuery("SELECT count(g.id) FROM Renshan\DetectorBundle\Entity\ReqGroup g WHERE g.user = ?1");
        $query->setParameter(1, $user);

        $result = $query->getResult();

        return $result[0][1];
    }

    /**
     *
     * 分页获取某个用户下的接口分组
     *
     * @param   integer $page
     * @param   ingeter $page_size
     *
     * @return  array
     */
    public function pagination($page = 1, $page_size = 20)
    {
        $user = $this->user_service->getUser();

        $page_size = $page_size ? $page_size : 20;

        $total = $this->count();
        $max_page = ceil($total / $page_size);

        $page = $page < 1 ? 1 : $page;
        $page = $page > $max_page ? $max_page : $page;

        $offset = ($page - 1) * $page_size;

        if ($total === 0) {
            return [
                'current_page' => 1, 
                'max_page' => 1,
                'total' => 0,
                'page_size' => (int)$page_size,
                'data' => []
            ];
        }

        $qb = $this->container->get('doctrine')->getManager()->createQueryBuilder();

        $qb->select('g')
            ->from('Renshan\DetectorBundle\Entity\ReqGroup', 'g')
            ->where("g.user = ?1")
            ->setFirstResult( $offset )
            ->setMaxResults( $page_size )
            ->setParameter(1, $user);

        $query = $qb->getQuery();

        $groups         = $query->getResult();
        $groups_array   = $query->getArrayResult();

        $maps           = [];

        foreach ($groups as $group) {
            $id         = $group->getId();
            $targets    = $group->getTargets();
            $maps[$id]  = [];

            foreach ($targets as $target) {
                $tmp = [];
                $tmp['id']      = $target->getId();
                $tmp['title']   = $target->getTitle();

                array_push($maps[$id], $tmp);
            }

        }

        foreach ($groups_array as $k => $group_array) {
            $groups_array[$k]['targets'] = $maps[$group_array['id']];
        }

        return [
            'current_page' => (int)$page, 
            'max_page' => (int)$max_page,
            'total' => (int)$total,
            'page_size' => (int)$page_size,
            'data' => $groups_array
        ];
    }

    /**
     *
     * 删除一个分组
     *
     * @param integer   $id
     * 
     * @return array
     */
    public function delete($id)
    {
        $em     = $this->container->get('doctrine')->getManager();
        $rep    = $em->getRepository('Renshan\DetectorBundle\Entity\ReqGroup');

        $group  = $rep->find($id);

        if ($group == null) {
            return ['code' => -1, 'message' => '分组信息不存在'];
        }

        $user   = $this->user_service->getUser();

        if ($group->getUser()->getId() != $user->getId()) {
            return ['code' => -1, 'message' => '分组不可删除'];
        }

        $em->remove($group);

        $results = $group->getResults();

        foreach ($results as $result) {
            $em->remove($result);
        }

        $em->flush();

        return ['code' => 1];
    }

    /**
     *
     * 更新分组
     *
     * @return array
     */
    public function update()
    {
        $ret_array = ['code' => -1];

        $params = $this->request->get('params');

        if ($params === null) {
            $ret_array['message'] = '参数不能为空';
            return $ret_array;
        }

        $params = json_decode($params, true);

        if (json_last_error() !== 0) {
            $ret_array['message'] = '参数格式错误';
            return $ret_array;
        }

        /** 数据不全 **/
        if (!array_key_exists('title', $params)  || 
            !array_key_exists('timing', $params) || 
            !array_key_exists('keys', $params)   || 
            !array_key_exists('id', $params)) {

            $ret_array['message'] = '参数不完整';
            return $ret_array;
        }

        /** 少于2个接口不能作为一组 **/
        if (count($params['keys']) < 2) {
            $ret_array['message'] = '接口个数必须大于1';
            return $ret_array;
        }

        $em = $this->container->get('doctrine')->getManager();

        $group = $em->getRepository('Renshan\DetectorBundle\Entity\ReqGroup')->find($params['id']);

        $group->setTitle($params['title']);
        $group->setTiming($params['timing']);

        $em->flush($group);

        if (!$group) {
            $ret_array['message'] = '分组不存在';
            return $ret_array;
        }

        $targets = $group->getTargets();

        $targets_id = [];

        foreach ($targets as $target) {
            array_push($targets_id, $target->getId());
        }

        /** 将要移除的接口的 ID */
        $removed_id = [];

        foreach ($targets_id as $key) {
            if (!in_array($key, $params['keys'])) {
                array_push($removed_id, $key);
            }
        }

        /** 将要加入的接口的 ID **/
        $added_id = [];

        foreach ($params['keys'] as $key) {
            if (!in_array($key, $targets_id)) {
                array_push($added_id, $key);
            }
        }

        /** 从接口列表中移除 **/
        if (count($removed_id) !== 0) {
            $rqb = $em->createQueryBuilder();

            $rqb->select('t')
                ->from('Renshan\DetectorBundle\Entity\Target', 't')
                ->where($rqb->expr()->in('t.id', $removed_id));

            $query      = $rqb->getQuery();
            $removed_targets    = $query->getResult();

            foreach ($removed_targets as $target)  {
                $target->removeReqGroup($group);
                $em->persist($target);
            }
        }

        /** 向接口组中添加接口  **/
        if (count($added_id) !== 0) {
            $aqb = $em->createQueryBuilder();

            $aqb->select('t')
                ->from('Renshan\DetectorBundle\Entity\Target', 't')
                ->where($aqb->expr()->in('t.id', $added_id));

            $query          = $aqb->getQuery();
            $added_targets  = $query->getResult();

            foreach ($added_targets as $target)  {
                $target->addReqGroup($group);
                $em->persist($target);
            }
        }

        $em->flush();

        return ['code' => 1];
    }

    public function detect()
    {
        $id = $this->request->get('id');

        $em  = $this->container->get('doctrine')->getManager();
        $rep = $em->getRepository('Renshan\DetectorBundle\Entity\ReqGroup'); 

        $group = $rep->find($id);


        if ($group == null) {
            return ['code' => -1, 'results' => []];
        }

        $targets = $group->getTargets();

        foreach ($targets as $target) {
            $this->detectSingle($target, $group);
        }

        $results = [];

        foreach ($this->results as $k => $result) {
            $tmp = [];

            $tmp['duration']    = $result->getDuration();
            $tmp['satus_code']  = $result->getStatusCode();
            //$tmp['body']        = $result->getBody();
            $tmp['headers']     = $result->getHeaders();

            $results[$k] = $tmp;
            $em->persist($result);
        }

        $em->flush();
        return ['code' => 1, 'results' => $results];
    }

    public function detectSingle($target, $group)
    {

        $headers = new Headers;

        $headers_array = $target->getHeaders();

        foreach ($headers_array as $k => $v) {
            $headers->set($k, $v);
        }

        $this->target = $target;

        $request = new Request($target->getUrl(), $target->getMethod(), $headers, $target->getParameters(), 1);

        $request->setAfterSend(function($time, $response) use($target, $group) {
            $this->afterSend($time, $response, $target, $group);
        });

        $request->send();
    }

    public function afterSend($time, $response, $target, $group)
    {
        $result = new ResultEntity;

        $result->setBody($response->getBody());
        $result->setHeaders($response->getHeaders()->getAll());
        $result->setStatusCode($response->getStatusCode());
        $result->setDuration($response->getRequestTime());
        $result->setTime(new \DateTime());
        $result->setReqGroup($group);

        $this->results[$target->getId()] = $result;
    }

}
